package com.denghq.projectbuilder.component.config.domain;

import com.denghq.projectbuilder.component.config.metadata.ConfigDescriptor;
import com.denghq.projectbuilder.component.config.metadata.ConfigOptionDescriptor;
import com.denghq.projectbuilder.component.config.metadata.enums.ConfigValueTypeEnum;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
public abstract class ConfigAutoRegister {

    private static Boolean registered = false;


    /**
     * 所有的配置类描述信息，需要过滤掉不需要注册的配置类
     */
    private final List<ConfigDescriptor> configDescriptorList;

    private final String appNo;

    @Getter
    private final LinkedHashMap<String, Long> consulIndexes;

    public ConfigAutoRegister(List<ConfigDescriptor> configDescriptorList, String appNo) {
        this.configDescriptorList = configDescriptorList;
        //this.properties = configProperties;
        this.appNo = appNo;
        this.consulIndexes = Maps.newLinkedHashMap();
    }


    public void registe() {
        if (!registered) {
            registered = true;
            List<ConfigDescriptor> currentConfigs;
            List<ConfigDescriptor> remoteConfigs;
            List<ConfigDescriptor> newConfigs;
            //1.过滤掉不用注册的配置信息
            currentConfigs = getAutoRegisterConfigs(configDescriptorList);
            //2.获取远端的配置信息
            remoteConfigs = getConfigsFromRemote(currentConfigs);
            //3.合并配置信息
            newConfigs = getNewConfigs(currentConfigs, remoteConfigs);
            //4.写入新的配置类描述信息
            writeConfigToRemote(newConfigs);
        }
    }

    protected abstract List<ConfigDescriptor> getConfigsFromRemote(List<ConfigDescriptor> currentConfigs);

    /**
     * 4.写入新的配置类描述信息
     *
     * @param configs
     */
    protected abstract void writeConfigToRemote(List<ConfigDescriptor> configs);


    /**
     * 3.更新老的配置类描述信息
     *
     * @param localConfigs
     * @param remoteConfigs
     * @return
     */
    private List<ConfigDescriptor> getNewConfigs(List<ConfigDescriptor> localConfigs, List<ConfigDescriptor> remoteConfigs) {
        List<ConfigDescriptor> res = Lists.newArrayList();
        if (!CollectionUtils.isEmpty(localConfigs)) {
            if (CollectionUtils.isEmpty(remoteConfigs)) {
                return localConfigs;
            }
            localConfigs.forEach(c -> {
                ConfigDescriptor oldConfig;
                boolean find = false;
                String categoryNo = c.getCategoryNo();
                for (int i = 0, len = remoteConfigs.size(); i < len; i++) {
                    oldConfig = remoteConfigs.get(i);
                    if (oldConfig.getCategoryNo().equals(categoryNo)) {
                        //校验
                        find = true;
                        validate(c, oldConfig);
                        //合并value
                        mergeOptionSettingValue(c.getOptionSettings(), oldConfig.getOptionSettings());
                        res.add(c);
                        break;
                    }
                }

                //未找到直接合并
                if (!find) {
                    res.add(c);
                }
            });
        }
        return res;
    }

    /**
     * 合并远端配置的值到配置类
     *
     * @param localOptionSettings
     * @param remoteOptionSettings
     */
    private void mergeOptionSettingValue(List<ConfigOptionDescriptor> localOptionSettings, List<ConfigOptionDescriptor> remoteOptionSettings) {
        if (!CollectionUtils.isEmpty(localOptionSettings) && !CollectionUtils.isEmpty(remoteOptionSettings)) {
            for (int k = 0, lenK = localOptionSettings.size(); k < lenK; k++) {
                ConfigOptionDescriptor local = localOptionSettings.get(k);
                if (local == null) return;
                for (int i = 0, len = remoteOptionSettings.size(); i < len; i++) {
                    ConfigOptionDescriptor remote = remoteOptionSettings.get(i);
                    if (null == remote) return;
                    if (null != local.getConfigKey() && local.getConfigKey().equals(remote.getConfigKey())) {
                        if (remote.getConfigValue() != null) {
                            local.setConfigValue(remote.getConfigValue());
                        } else {
                            if (local.getDefaultConfigValue() == null && local.getConfigValueType() == ConfigValueTypeEnum.BOOLEAN.getValue()) {
                                local.setConfigValue(false);
                            } else {
                                local.setConfigValue(local.getDefaultConfigValue());
                            }

                        }
                        break;
                    }
                }
            }
        }
    }

    private void validate(ConfigDescriptor c, ConfigDescriptor oldConfig) {
        if (c.getCategoryNo().equals(oldConfig.getCategoryNo())) {
            if (c.isAutoRegiste()) {
                Assert.isTrue(c.getAppNo().equals(appNo), "无法注册【" + c.getCategoryName() + "】配置，原因：appNo非法，只能注册属于本服务的配置。");
                Assert.isTrue(c.getAppNo().equals(oldConfig.getAppNo()), "注册【" + c.getCategoryName() + "】配置失败,该配置已经注册在【" + oldConfig + "】");
            }
        }

    }

    /**
     * 1.过滤掉不用注册的配置信息
     *
     * @param configDescriptorList
     * @return
     */
    private List<ConfigDescriptor> getAutoRegisterConfigs(List<ConfigDescriptor> configDescriptorList) {

        List<ConfigDescriptor> configs = Lists.newArrayList();
        if (!CollectionUtils.isEmpty(configDescriptorList)) {
            configs = configDescriptorList.stream().filter(e -> e.isAutoRegiste()).collect(Collectors.toList());
        }
        return configs;
    }

}
